iT邦幫忙

2023 iThome 鐵人賽

DAY 2
0
自我挑戰組

解三十天的 CodeWars系列 第 2

Simple Pig Latin

  • 分享至 

  • xImage
  •  

CodeWars 題目

Link

難度

5 kyu

題目

  • 每一個首字元移動到字尾。
  • 字尾加上 "ay”。
  • 標點符號保持不變。

思路

移動:從字元中「刪除」,再加上 ay。

以 replace 實作,利用正則驗證是否字首為 a-zA-z;在這一步如果是標點符號等則會被忽略,因為不會符合正則;符合正則的 match,則用變數暫存起來再字尾補上。

pseudo code

str.split

str.map(item => 
  let str
  item.replace(/^a-z/i, match =>
    str = match
    return ""
  )
  return item + str + "ay"
)

str.join(" ")

實作

function pigIt(str) {
   str = str.split(" ").map((item) => {
      let str = "";
      item = item.replace(/^[a-z]/i, (match) => {
         str = match + "ay";
         return "";
      })
      return item + str;
   })
   return str.join(" ");
}

split 拆解成陣列後,用 map 去迭代每一個陣列元素。
/^[a-z]/i 會獲取字首的一個字元,驗證是否為 a-z 並且忽視字母大小寫。
如果有捕獲到 match,把符合的內容暫存變數並加上 ay;如果不符合正則的驗證,則不會進入這個函數。
將字首字元暫存後,返回空字串、也就是替代掉了首字元。

map 返回處理後,符合原始陣列長度的新陣列,這裡修正了 pseudo code 忽略的錯誤。
return item + str + "ay" 這一段會把 ay 也加進標點符號之後,因此實作時把這段加到了 map 之中,外層宣告的 str 就會維持空字串。

最後返回 join 後的結果。

他人的解法

function pigIt(str){
  return str.replace(/(\w)(\w*)(\s|$)/g, "\$2\$1ay\$3")
}

在正則表達式中,() 符號會拆分捕獲的條件。

  • 第一個 (\w),尋找單一個 [A-Za-z0-9_],也就是字首字元。例如:Thing。
  • 第二個 (\w*),尋找出現零到多次的 [A-Za-z0-9_],也就是字首後的字元。例如:Thing
  • 第三個 (\s|$)\s 表示空白、空格、換行等符號,$ 表示結尾。
  • g 表示正則會驗證完整個字串。

replace 第二參數如果帶入函數,其中會帶入的參數:

replacer(match, $1, $2, /* …, */ $N, offset, string, groups)

整個正則表達式 /(\w)(\w*)(\s|$)/g,會捕獲符合條件的字串,也就是 match; $1、$2 這種表示方式是對應第一參數的()

Hello world ! 為例,match 會捕獲 "Hello " 以及 "world "
$1 $2 $3 分別是 "H""ello"" ""w""orld"" "
也就是說 \$2\$1ay\$3,$1 在字首字元後加上 ay,並與 $2 調換位置,$3 則維持字尾的位置。

而其餘標點符號根本不會被正則捕獲,不受影響。

心得

寫 pseudo code 的經驗還太少了,自己還沒辦法很好的運用。


上一篇
前言
下一篇
Human Readable Time
系列文
解三十天的 CodeWars30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言